#include "rkmedia_data_process.h"

extern videoQueue *high_video_queue;
extern videoQueue *low_video_queue;
extern containerInfo *above_container_func;

AVPacket *put_high_video_to_ffmpeg_avpacket(AVPacket *pPacket)
{
    int ret = -1;
    video_data_packet *highPacket = high_video_queue->getVideoDataFromQueue();
    if (!highPacket)
    {
        cout << "highPacket is null..." << endl;
        return NULL;
    }
    else
    {
        // av_packet_unref(pPacket);
        ret = av_buffer_realloc(&pPacket->buf, highPacket->buffer_size + 70);
        if (ret)
        {
            cout << "high av_buffer_realloc failed ..." << endl;
            return NULL;
        }
        else
        {
            // cout << "high av_buffer_realloc success ..." << endl;
            memcpy(pPacket->buf->data, highPacket->buffer, highPacket->buffer_size);
            pPacket->size = highPacket->buffer_size;
            pPacket->data = pPacket->buf->data; // 数据缓冲
            pPacket->flags |= AV_PKT_FLAG_KEY;
            delete[] highPacket->buffer;
            delete highPacket;
            highPacket = NULL;
            return pPacket;
        }
    }
}

int per_convert_write_avpacket_to_context(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
{
    av_packet_rescale_ts(pkt, *time_base, st->time_base);
    pkt->stream_index = st->index;
    return av_interleaved_write_frame(fmt_ctx, pkt); // ！！！这个返回值用来判断是否正常写入帧，而无论是否成功写入，
                                                     // libavformat都会负责释放传入的AVPacket
                                                     // 如果加了判断加入加了return,有可能会因为DTS不是单调递增问题导致报错.....
}

int deal_high_video_avpacket(AVFormatContext *fmt_ctx, OutputStream *ost)
{
    int ret = -1;
    AVCodecContext *tmp = ost->ctx;
    AVPacket *high_video_packet = put_high_video_to_ffmpeg_avpacket(ost->pkt); // 因为再把视频流写道avpacket中时，已经给AVStreamRef进行realloc
    if (high_video_packet)
    {
        // high_video_packet->pts = ost->timestamp;
        high_video_packet->stream_index = 0;
        high_video_packet->pts = av_rescale_q(ost->timestamp, (AVRational){1, 1000000}, fmt_ctx->streams[0]->time_base);
        high_video_packet->dts = high_video_packet->pts;
        ost->timestamp++;
    }
    av_interleaved_write_frame(fmt_ctx, high_video_packet);
    av_packet_unref(high_video_packet);

    return 0;
}

void *camera_rga_thread(void *args)
{
    pthread_detach(pthread_self());
    RV1126_RGA_CONTAINER rga_container;
    above_container_func->get_rga_container(0, &rga_container);
    printf("rga_chn is %d\n", rga_container.rga_chn);

    map<string, rockx_face_feature_t> face_map = get_face_feature_to_map();
    cout << "-----------------Get face data from sqlite successful----------------" << endl;
    map<string, rockx_face_feature_t>::iterator face_iterator;

    MEDIA_BUFFER mb;
#if 1
    rockx_ret_t rk_ret;
    rockx_config_t *config = rockx_create_config();
    rk_ret = rockx_add_config(config, ROCKX_CONFIG_DATA_PATH, ROCKX_DATA_PATH);
    if (rk_ret != ROCKX_RET_SUCCESS)
    {
        cout << "rockx_add_config failed ..." << endl;
        return NULL;
    }

    rockx_handle_t face_det_handle;
    rk_ret = rockx_create(&face_det_handle, ROCKX_MODULE_FACE_DETECTION, config, sizeof(rockx_config_t));
    if (rk_ret != ROCKX_RET_SUCCESS)
    {
        cout << "face_det_handle rockx_create failed ..." << endl;
        return NULL;
    }

    rockx_handle_t face_landmarks_handle; // 这里的人脸关键点采集是进行人脸过滤和人脸对齐用的(人脸过滤是检测人脸的真实性，人脸对齐是为了矫正姿态和光线对特征值的采集影响)
    rk_ret = rockx_create(&face_landmarks_handle, ROCKX_MODULE_FACE_LANDMARK_5, config, sizeof(rockx_config_t));
    if (rk_ret != ROCKX_RET_SUCCESS)
    {
        cout << "face_landmarks_handle rockx_create failed ..." << endl;
        return NULL;
    }

    rockx_handle_t face_rec_handle;
    rk_ret = rockx_create(&face_rec_handle, ROCKX_MODULE_FACE_RECOGNIZE, config, sizeof(rockx_config_t));
    if (rk_ret != ROCKX_RET_SUCCESS)
    {
        cout << "face_rec_handle rockx_create failed ..." << endl;
        return NULL;
    }
#endif

    rockx_object_t *max_face = NULL;
    rockx_object_t *cur_face = NULL;

    while (1)
    {
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, rga_container.rga_chn, -1);
        if (!mb)
        {
            printf("Get rga mb failed...\n");
            return NULL;
        }
        else
        {
#if 1
            rockx_image_t img;
            memset(&img, 0, sizeof(rockx_image_t));
            rkMB_IMAGE_INFO mbInf;
            memset(&mbInf, 0, sizeof(rkMB_IMAGE_INFO));
            RK_MPI_MB_GetImageInfo(mb, &mbInf);
            img.width = mbInf.u32Width;
            img.height = mbInf.u32Height;
            img.pixel_format = ROCKX_PIXEL_FORMAT_RGB888;
            img.size = RK_MPI_MB_GetSize(mb);
            img.data = (uint8_t *)RK_MPI_MB_GetPtr(mb);

            rockx_object_array_t face_array;
            memset(&face_array, 0, sizeof(rockx_object_array_t));
            rk_ret = rockx_face_detect(face_det_handle, &img, &face_array, NULL);
            if (rk_ret != ROCKX_RET_SUCCESS)
            {
                cout << "rockx_face_detect error ..." << endl;
                break;
            }

            max_face = NULL;
            if (face_array.count > 0)
            {
#ifdef DEBUG
                cout << "Get face object success..." << endl;
#endif
                for (int i = 0; i < face_array.count; i++)
                {
#if 1 //////////////人脸过滤，人脸真实性筛选
                    int is_false_face;
                    rk_ret = rockx_face_filter(face_landmarks_handle, &img, &face_array.object[i].box, &is_false_face);
                    if (rk_ret != ROCKX_RET_SUCCESS)
                    {
                        printf("ERROR: rockx_face_filter error %d\n", rk_ret);
                    }
                    if (is_false_face)
                    {
                        continue;
                    }
#endif
#ifdef DEBUG
                    cout << "face detect score: " << face_array.object[i].score << endl;
#endif
                    int left = face_array.object[i].box.left;
                    int top = face_array.object[i].box.top;
                    int right = face_array.object[i].box.right;
                    int bottom = face_array.object[i].box.bottom;
                    int width = right - left;
                    int height = bottom - top;
#ifdef DEBUG
                    cout << "box position(left, top, right, bottom):"
                         << " " << face_array.object[i].box.left
                         << " " << face_array.object[i].box.top
                         << " " << face_array.object[i].box.right
                         << " " << face_array.object[i].box.bottom << endl;
#endif
#if 1
                    if (left < 0)
                    {
                        left = 0;
                    }
                    if (top < 0)
                    {
                        top = 0;
                    }
                    while ((left + width) > img.width)
                    {
                        width -= 16;
                    }
                    while ((top + height) > img.height)
                    {
                        height -= 16;
                    }

                    cur_face = &(face_array.object[i]);
                    if (max_face == NULL)
                    {
                        max_face = cur_face;
                    }
                    else
                    {
                        int cur_face_box_area = width * height;
                        int max_face_box_area = (max_face->box.right - max_face->box.left) * (max_face->box.bottom - max_face->box.top);
                        if (cur_face_box_area > max_face_box_area)
                        {
                            max_face = cur_face;
                        }
                    }
                    rockx_image_t align_img;
                    memset(&align_img, 0, sizeof(rockx_image_t));
                    rk_ret = rockx_face_align(face_landmarks_handle, &img, &(max_face->box), NULL, &align_img);
                    if (rk_ret != ROCKX_RET_SUCCESS)
                    {
                        cout << "rk rockx_face_align error ..." << endl;
                        break;
                    }

#endif
                    rockx_face_feature_t rk_face_feat;
                    memset(&rk_face_feat, 0, sizeof(rockx_face_feature_t));
                    rk_ret = rockx_face_recognize(face_rec_handle, &align_img, &rk_face_feat);
                    if (rk_ret != ROCKX_RET_SUCCESS)
                    {
                        cout << "rk rockx_face_recognize error ..." << endl;
                        break;
                    }
                    rockx_image_release(&align_img); // 释放对齐的图像
#ifdef DEBUG
                    cout << "Face recognize start..." << endl;
#endif
                    float similar = 0.0;
                    string name = "";
                    bool is_success = false;
                    for (face_iterator = face_map.begin(); face_iterator != face_map.end(); face_iterator++)
                    {
                        rk_ret = rockx_face_feature_similarity(&face_iterator->second, &rk_face_feat, &similar);
                        if (rk_ret != ROCKX_RET_SUCCESS)
                        {
                            cout << "rockx_face_feature_similarity error ..." << endl;
                            break;
                        }
#ifdef DEBUG
                        cout << "face recognize val: " << similar << endl;
#endif
                        if (similar <= 1.0) // rockx相似度比对采用欧氏距离，越接近于0越准确
                        {
                            is_success = true;
                            break;
                        }
                        else
                        {
                            continue;
                        }
                    }
                    if (is_success == true)
                    {
                        name = face_iterator->first;
                    }
                    else
                    {
                        name = "";
                    }
                    Ptr<cv::freetype::FreeType2> font = freetype::createFreeType2();
                    font->loadFontData("/usr/share/fonts/source-han-sans-cn/SourceHanSansCN-Normal.otf", 0);
                    Rect face_rect = Rect(Point(left, top), Point(right, bottom));
                    Mat dst = Mat(img.height, img.width, CV_8UC3, img.data);
                    rectangle(dst, face_rect, Scalar(0, 0, 255), 2);
                    string rec_score = to_string(similar);
                    if (similar <= 1.0)
                    {
                        font->putText(dst, "识别成功: " + name, Point(left, top - 90), 50, Scalar(0, 255, 0), -1, LINE_8, 1);
                        font->putText(dst, "ED: " + rec_score, Point(left, top - 16), 50, Scalar(0, 255, 0), -1, LINE_8, 1);
                    }
                    else
                    {
                        font->putText(dst, "识别失败: " + name, Point(left, top - 90), 50, Scalar(0, 0, 255), -1, LINE_8, 1);
                        font->putText(dst, "ED: " + rec_score, Point(left, top - 16), 50, Scalar(0, 0, 255), -1, LINE_8, 1);
                    }
#ifdef DEBUG
                    cout << "The person name: " << name << endl
                         << endl;
#endif
                    dst.release();
                }
            }
#endif
            RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, 0, mb);
            RK_MPI_SYS_SendMediaBuffer(RK_ID_VO, 0, mb);
            RK_MPI_MB_ReleaseBuffer(mb);
            mb = NULL;
        }
    }
    face_map.erase(face_map.begin(), face_map.end());
    face_map.erase(face_iterator);
    rockx_destroy(face_det_handle);
    rockx_destroy(face_rec_handle);
    return NULL;
}

#if 0
void *camera_rga_res_thread(void *args)
{
    pthread_detach(pthread_self());
    MEDIA_BUFFER mb;
    RV1126_RGA_CONTAINER rga_res_container;
    above_container_func->get_rga_container(1, &rga_res_container);
    printf("rga_res_chn is %d\n", rga_res_container.rga_chn);
    while (1)
    {
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, rga_res_container.rga_chn, -1);
        if (!mb)
        {
            printf("Get rga_res mb failed...\n");
            return NULL;
        }
        else
        {
            // printf("Get rga mb success...\n");
            RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, 0, mb);
            RK_MPI_MB_ReleaseBuffer(mb);
        }
    }
    return NULL;
}
#endif

void *camera_venc_thread(void *args)
{
    pthread_detach(pthread_self());
    MEDIA_BUFFER mb;
    RV1126_VENC_CONTAINER venc_container;
    above_container_func->get_venc_container(0, &venc_container);
    printf("venc_chn is %d\n", venc_container.venc_chn);
    while (1)
    {
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, venc_container.venc_chn, -1);
        if (!mb)
        {
            printf("Get venc mb failed...\n");
            return NULL;
        }
        else
        {
            // printf("Get venc mb success...\n");
            video_data_packet *high_video_packet = new video_data_packet;
            high_video_packet->buffer = new unsigned char[RK_MPI_MB_GetSize(mb)];
            memcpy(high_video_packet->buffer, RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb));
            high_video_packet->buffer_size = RK_MPI_MB_GetSize(mb);
            high_video_queue->putVideoDataToQueue(high_video_packet);
            RK_MPI_MB_ReleaseBuffer(mb);
        }
    }
    return NULL;
}

void *ffmpeg_high_video_push_thread(void *args)
{
    pthread_detach(pthread_self());
    int ret = -1;
    ffmpegInfo ffmpeg_config = *(ffmpegInfo *)args;
    delete (ffmpegInfo *)args;
    while (1)
    {
        ret = deal_high_video_avpacket(ffmpeg_config.fmt_ctx, &ffmpeg_config.video_stream);
        if (ret)
        {
            cout << "ffmpeg_high_video_push_thread exist error..." << endl;
            return NULL;
        }
    }

    av_write_trailer(ffmpeg_config.fmt_ctx);
    free_stream(&ffmpeg_config.video_stream);
    avio_closep(&ffmpeg_config.fmt_ctx->pb);      // 关闭AVIOContext
    avformat_free_context(ffmpeg_config.fmt_ctx); // 释放这个AVFormatContext以及和它关联的所有Stream
    return NULL;
}
